package com.thghh.bcode.ftl;

import com.squareup.javapoet.*;
import com.thghh.bcode.io.ByteArrayAppendable;
import com.thghh.bcode.model.Property;
import com.thghh.bcode.model.PropertyModel;
import com.thghh.bcode.model.SourceFileModel;
import com.thghh.table.BeanColumn;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import javax.lang.model.element.Modifier;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Zhikang.Peng
 * @version 1.0
 * @email thghh@qq.com
 * @date 2020/12/9 16:47
 */
public class GenerateJavaSource {

    public GenerateJavaSource() {
    }

    public byte[] generateSourceCodeByTemplate(SourceFileModel sourceFileModel, List<PropertyModel> properties) throws IOException, TemplateException {
        Template template = FreeMarkerTemplateUtils.getTemplate("PropertyModel.ftl");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("package_name", sourceFileModel.getPackageName());
        dataMap.put("class_name", sourceFileModel.getClassName());
        dataMap.put("properties", properties);
        ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
        Writer writer = new OutputStreamWriter(new BufferedOutputStream(output));

        // Create the builder:
        BeansWrapperBuilder builder = new BeansWrapperBuilder(Configuration.getVersion());
        // Set desired BeansWrapper configuration properties:
        builder.setUseModelCache(true);
        builder.setExposeFields(true);
        template.process(dataMap, writer, builder.build());
        writer.flush();
        return output.toByteArray();
    }

    public byte[] generateSourceCodeByJavaPoet(SourceFileModel sourceFileModel, List<PropertyModel> properties) throws IOException, TemplateException {
        // class type define
        AnnotationSpec equalsAndHashCode =  AnnotationSpec.builder(lombok.EqualsAndHashCode.class)
                .addMember("callSuper","$N", "true").build();
        TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(sourceFileModel.getClassName())
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(lombok.Data.class)
                .superclass(Property.class)
                .addAnnotation(equalsAndHashCode);

        // field
        for (PropertyModel property : properties) {
            AnnotationSpec beanColumn = AnnotationSpec.builder(BeanColumn.class)
                    .addMember("name", "$S",property.getDisplayPropertyName())
                    .addMember("index", "$N",  String.valueOf(property.getPropertyIndex()))
                    .addMember("editable", "$N", String.valueOf( property.isEditable()))
                    .build();
            FieldSpec fieldSpec = FieldSpec.builder(property.getPropertyType(), property.getPropertyName(), Modifier.PRIVATE)
                    .addAnnotation(beanColumn).build();
            typeBuilder.addField(fieldSpec);
        }

        TypeSpec classTypeSpec = typeBuilder.build();

        JavaFile javaFile = JavaFile.builder(sourceFileModel.getPackageName(), classTypeSpec).build();

        ByteArrayAppendable writer = new ByteArrayAppendable();
        javaFile.writeTo(writer);
        return writer.toByteArray();
    }
}
